#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/11/8 15:47
# @Author  : youfeng
import os
import time
from datetime import datetime

from config import SFTP_CONFIG
from sftp import Sftp


# 基本上传流程
class BaseUpload(object):
    # 保存最长时间差
    __MAX_SAVE_TIME = 24 * 3600 * 7

    # 备份标识
    __BAK_TAG = ".databak"

    def __init__(self, data_path, log):
        self.log = log
        self.__data_path = data_path
        self.__sftp = Sftp(SFTP_CONFIG['host'], SFTP_CONFIG["port"], SFTP_CONFIG["user"], SFTP_CONFIG["password"], log)

    # 这里需要继承, 根据文件名 解析出version，主要用于basic_data解析
    def get_remote_path(self, file_name):
        pass

    # 计算时间差
    def __is_expire(self, file_path):
        now_timestamp = time.time()
        timestamp = os.path.getmtime(file_path)
        if now_timestamp - timestamp >= self.__MAX_SAVE_TIME:
            return True

        return False

    @staticmethod
    def __get_current_time():
        return datetime.now().strftime("%Y%m%d%H%M%S")

    def __get_local_path_list(self):
        local_path_list = []
        # 扫描MD5文件
        for md5_name in os.listdir(self.__data_path):
            md5_path = os.path.join(self.__data_path, md5_name)
            if not os.path.isfile(md5_path):
                continue

            if md5_name.endswith(".md5"):
                tar_name = md5_name.split(".")[0] + ".tgz"
                file_name = md5_name.split(".")[0]
                tar_path = os.path.join(self.__data_path, tar_name)
                self.log.info("当前需要上传文件MD5: file_name = {}".format(md5_name))
                self.log.info("当前需要上传文件压缩包: file_name = {}.tgz".format(tar_name))

                # 判断tgz文件是否存在
                if not os.path.exists(tar_path):
                    self.log.error("当前md5文件没有对应的tgz文件: base_path = {} md5_file = {}".format(
                        self.__data_path,
                        md5_name))
                    continue

                local_path_list.append({
                    "file_name": file_name,
                    "md5_name": md5_name,
                    "tar_name": tar_name,
                    "md5_path": md5_path,
                    "tar_path": tar_path
                })
        return local_path_list

    def __bak_success_file(self, file_info_dict):
        # 获得当前时间切面
        timestamp = "_{}{}".format(self.__get_current_time(), self.__BAK_TAG)
        md5_path = file_info_dict.get("md5_path")
        tar_path = file_info_dict.get("tar_path")

        try:
            # 先删除已存在的文件
            os.remove(md5_path + timestamp)
            os.remove(tar_path + timestamp)

            os.rename(md5_path, md5_path + timestamp)
            os.rename(tar_path, tar_path + timestamp)
        except Exception as e:
            self.log.error("文件备份异常: md5_path = {}".format(md5_path))
            self.log.error("文件备份异常: tar_path = {}".format(tar_path))
            self.log.exception(e)

    # 发送数据到sftp
    def __put_to_sftp(self, local_path, remote_path):
        if not os.path.exists(local_path):
            self.log.error("本地文件不存在: local_path = {}".format(local_path))
            return False

        if not isinstance(remote_path, basestring):
            self.log.error("ftp远端路径参数错误: remote_path = {}".format(remote_path))
            return False

        return self.__sftp.put(local_path, remote_path)

    # 清理过期文件
    def __clear_expire_file(self):
        for file_name in os.listdir(self.__data_path):
            file_path = os.path.join(self.__data_path, file_name)
            # 如果不是文件则直接跳过
            if not os.path.isfile(file_path):
                continue

            # 判断是否是备份文件
            if not file_name.endswith(self.__BAK_TAG):
                continue

            # 判断文件是否过期了
            if not self.__is_expire(file_path):
                continue

            try:
                os.remove(file_path)
                self.log.info("当前文件删除成功: file_path = {}".format(file_path))
            except Exception as e:
                self.log.error("删除文件失败: file_path = {}".format(file_path))
                self.log.exception(e)

    def close(self):
        if self.__sftp is not None:
            self.__sftp.close()
            self.__sftp = None

    def upload(self):

        if self.__sftp is None:
            self.log.error("sftp未连接...")
            return

        local_path_list = self.__get_local_path_list()
        for file_info_dict in local_path_list:
            file_name = file_info_dict.get("file_name")
            if file_name is None:
                continue

            # 获得远端上传路径
            remote_path = self.get_remote_path(file_name)
            if not isinstance(remote_path, basestring):
                self.log.error("抽取远程路径失败: data_path = {} file_name = {}".format(
                    self.__data_path, file_name))
                continue

            # 创建文件夹
            self.__sftp.mkdir(remote_path)

            # 获取本地文件路径
            local_path = file_info_dict.get("tar_path")

            # 如果上传是成功的，则直接备份文件
            if self.__put_to_sftp(local_path, remote_path):
                self.__bak_success_file(file_info_dict)

        # 清理过期文件
        self.__clear_expire_file()

        self.log.info("当前路径扫描完成: data_path = {}".format(self.__data_path))
